/**
 * Copyright 2012 Roger Cockshutt
 * krakenbrau@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.parallelrl.process;

import java.util.List;

import com.googlecode.parallelrl.data.ECSLevel;
import com.googlecode.parallelrl.data.LevelProvider;
import com.googlecode.parallelrl.data.ecs.ECSManager;
import com.googlecode.parallelrl.display.Colors;
import com.googlecode.parallelrl.display.GameLogger;
import com.googlecode.parallelrl.util.MersenneTwister;
import com.googlecode.parallelrl.util.Names;
import com.googlecode.parallelrl.util.Point2D;

/**
 * @author Roger Cockshutt
 *
 */
public abstract class Actions {
	
	public static void move(Long entity, String parameters) {
		Point2D pos = Point2D.valueOf(parameters);
		if (pos != null && LevelProvider.getCurrentLevel().isMovableTo(pos)) {
			Long time = 100L;
			BehaviourManager.calculateSecondaries(entity, Names.movementSpeed);
			if (ECSManager.hasComponent(entity, Names.movementSpeed)) {
				time -= ECSManager.getComponent(entity, Names.movementSpeed).doubleValue().longValue();
			}
			time += Game.currentStep;
			EventSystem.newEvent(Game.currentStep, entity, "set", Names.position, parameters);
			EventSystem.newEvent(time, entity, "turn", (String)null);
		} else {
			EventSystem.newEvent(Game.currentStep, entity, "turn", (String)null);
		}
	}
	
	public static void add(Long entity, String parameters) {
		String[] splitParams = parameters.split(",", 2);
		if (splitParams.length == 2) {
			String component = splitParams[0];
			Double addValue = Double.valueOf(splitParams[1]);
			if (ECSManager.hasComponent(entity, component)) {
				Double origValue = ECSManager.getComponent(entity, component).doubleValue();
				Double newValue = origValue + addValue;
				EventSystem.newEvent(Game.currentStep, entity, "set", component, newValue.toString());
			}
		}
	}
	
	public static void set(Long entity, String parameters) {
		String[] splitParams = parameters.split(",", 2);
		if (splitParams.length == 2) {
			String component = splitParams[0];
			String value = splitParams[1];
			ECSManager.setComponent(entity, component, value);
		}
	}
	
	@SuppressWarnings("unused")
	public static void kill(Long entity, String parameters) {
		ECSManager.killEntity(entity);
	}
	
	@SuppressWarnings("unused")
	public static void spawn(Long entity, String parameters) {
		String[] splitParams = parameters.split(",", 2);
		if (splitParams.length == 2) {
			String assemblage = splitParams[0];
			Point2D pos = Point2D.valueOf(splitParams[1]);
			Long newEntity = ECSManager.createEntityFromAssemblage(assemblage);
			BehaviourManager.calculateSecondaries(newEntity);
			EventSystem.newEvent(Game.currentStep, newEntity, "set", Names.position, pos.toString());
			EventSystem.newEvent(Game.currentStep, newEntity, "turn", (String)null);
		}
	}
	
	@SuppressWarnings("unused")
	public static void pickup(Long entity, String parameters) {
		if (ECSManager.hasComponent(entity, Names.position)) {
			Point2D pos = ECSManager.getComponent(entity, Names.position).coordinateValue();
			List<Long> items = ECSManager.getAllEntitiesPossessingComponentValue(Names.position, pos.toString());
			for (Long id : items) {
				if (id != entity) {
					EventSystem.newEvent(Game.currentStep, id, "remove", Names.position);
					EventSystem.newEvent(Game.currentStep, entity, "append", Names.inventory, id.toString());
					break;
				}
			}
		}
		EventSystem.newEvent(Game.currentStep, entity, "turn", (String)null);
	}
	
	public static void append(Long entity, String parameters) {
		String[] splitParams = parameters.split(",", 2);
		if (splitParams.length == 2) {
			String component = splitParams[0];
			String appValue = splitParams[1];
			String origValue = "";
			if (ECSManager.hasComponent(entity, component)) {
				origValue = ECSManager.getComponentValue(entity, component) + ",";
			}
			String newValue = origValue + appValue;
			EventSystem.newEvent(Game.currentStep, entity, "set", component, newValue);
		}
	}
	
	@SuppressWarnings("unused")
	public static void turn(Long entity, String parameters) {
		BehaviourManager.act(entity);
	}
	
	public static void remove(Long entity, String parameters) {
		ECSManager.removeComponent(entity, parameters);
	}
	
	public static void strike(Long entity, String parameters) {
		Point2D pos = Point2D.valueOf(parameters);
		Long target = ECSLevel.getFirstEntityWith(pos, "Behaviour", null);
		if (target != null) {
			BehaviourManager.calculateSecondaries(
					entity, Names.physicalSpeed, Names.physicalAccuracy, Names.physicalAttack);
			BehaviourManager.calculateSecondaries(target, Names.physicalEvasion, Names.physicalDefense);
			Integer time = 100;
			Double pAtkSpd = ECSManager.getComponent(entity, "PhysicalSpeed").doubleValue();
			time -= pAtkSpd.intValue();
			Double pAccAtkr = ECSManager.getComponent(entity, "PhysicalAccuracy").doubleValue();
			Double pEvaDfndr = ECSManager.getComponent(target, "PhysicalEvasion").doubleValue();
			Double hitMargin = 50D + (pAccAtkr - pEvaDfndr);
			Integer approxHitMargin = (int) (hitMargin * 10);
			Integer roll = MersenneTwister.getNext(1000);
			if (roll < approxHitMargin) {
				Double pDefDfndr = ECSManager.getComponent(target, "PhysicalDefense").doubleValue();
				Double pAtkAtkr = ECSManager.getComponent(entity, "PhysicalAttack").doubleValue();
				Integer dmgMod = MersenneTwister.getNext(50) + 75;
				Integer defMod = MersenneTwister.getNext(50) + 75;
				Integer damageDealt = (int) ((pAtkAtkr * (dmgMod / 100D)) - (pDefDfndr * (defMod / 100D)));
				if (damageDealt < 0) {
					damageDealt = 0;
				}
				
				EventSystem.newEvent(Game.currentStep, target, "add", Names.health, Integer.valueOf(0 - damageDealt).toString());
				Long killEvent = EventSystem.newEvent(Game.currentStep, target, "kill", (String)null);
				EventSystem.setCondition(
						killEvent, Names.health + "," + target.toString(), "<=", String.valueOf(0));
				EventSystem.newEvent(Game.currentStep + time, entity, "turn", (String)null);
				
				GameLogger.get().addMessage("The " + ECSManager.getComponent(entity, "FormalName").value() + " strikes the "
						+ ECSManager.getComponent(target, "FormalName").value() + ", dealing " + damageDealt
						+ " damage!", Colors.libTCOD.crimson.normal);
			} else {
				EventSystem.newEvent(Game.currentStep + time, entity, "turn", (String)null);
				GameLogger.get().addMessage("The " + ECSManager.getComponent(target, "FormalName").value() + 
						" quickly dodges the " + ECSManager.getComponent(entity, "FormalName").value() +
						"'s strike!", Colors.libTCOD.azure.normal);
			}
		} else {
			EventSystem.newEvent(Game.currentStep , entity, "turn", (String)null);
		}
	}

}
